#include <middleware/gm_api/skfapi.h>
#include <middleware/gm_api/skfapi_ex.h>
#include <middleware/mk_lib/mk_auto_mutex.h>
#include <middleware/mk_lib/mk_utility.h>
#include <middleware/mk_lib/mk_logger.h>
#include <middleware/apdu/apdu.lib/apdu_lib_cryption_mgr.h>
#include <middleware/apdu/apdu.lib/apdu_lib_dev_config.h>

#include "gm_global.h"
#include "gm_defs.h"
#include "../gm_data_mgr/gm_sc_mgr.h"

ULONG DEVAPI SKF_GetKeyInfo(HANDLE hKey, ULONG * algoId, HANDLE * appHandle, HANDLE * devHandle)
{
	MK_AUTO_MUTEX
		DBG_LOGMSG("enter SKF_GetKeyInfo()");

	ULONG			lRslt = SAR_OK;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	* algoId = pkey->Algid();
	* appHandle = pApp->get_handle();
	* devHandle = pDev->get_handle();

END_OF_FUN:
	DBG_LOGMSG("leave SKF_GetKeyInfo(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_EncryptInit (HANDLE hKey, BLOCKCIPHERPARAM EncryptParam)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_EncryptInit()");

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	int maxTrans = 0;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_EncryptInitHS(hKey, EncryptParam);
	}

	if(pkey->check_iv_len(EncryptParam.IVLen) != SAR_OK)
	{
		lRslt = SAR_INVALIDPARAMERR;
		ERROR_THROW(lRslt);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();
	
	//Only for high speed 
	app_dev_enable_high_speed(hdev, 1);
	//

	lRslt = app_encrypt_init(hdev, app_id, cont_id, pkey->key_id(), EncryptParam.IV, 
		EncryptParam.IVLen, EncryptParam.PaddingType, EncryptParam.FeedBitLen);
	ERROR_THROW_APDU(lRslt)

	maxTrans = pDev->get_max_apdu_len();
	
	pkey->set_padding_type(EncryptParam.PaddingType);
	pkey->init_mem_stream(maxTrans * 2);

END_OF_FUN:
	DBG_LOGMSG("leave SKF_EncryptInit(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_Encrypt(HANDLE hKey, BYTE * pbData, ULONG ulDataLen, 
						 BYTE *pbEncryptedData, ULONG *pulEncryptedLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_Encrypt(), ulDataLen=%ld", ulDataLen);

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	ULONG			ulEncryptedTempdatalen = 0;
	ULONG			ulEncrypted_len = ulDataLen + get_max_transmit_len();
	BYTE			*pEncrytedTempdata = NULL;
	BYTE			*encrypted_ptr = NULL;

	BYTE			*header = NULL;
	BYTE			pFinalData[32] = {0};
	ULONG			_lastlen = 0;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;
	int expSize = 0;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}
	
	//if high speed device
	 if(pDev->if_support_hs())
	 {
		 return SKF_EncryptHS(hKey, pbData, ulDataLen, pbEncryptedData, pulEncryptedLen);
	 }

	if(SAR_OK != pkey->check_alg_data_len(ulDataLen) )
	{
		lRslt = SAR_INVALIDPARAMERR;
		goto END_OF_FUN;
	}

	pEncrytedTempdata = new BYTE[ulEncrypted_len];

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	if(pbEncryptedData == NULL)
	{
		*pulEncryptedLen = pkey->get_padding_result_len(ulDataLen);
		goto END_OF_FUN;
	}
	
	expSize = pkey->get_padding_result_len(ulDataLen);
	TRACE_ASSERT_LEN(*pulEncryptedLen, expSize);

	header = pkey->get_stream_mgr()->push_data(pbData, ulDataLen);//
	memset(pEncrytedTempdata, 0, ulEncrypted_len);

	encrypted_ptr = pEncrytedTempdata;

	while(_lastlen = pkey->get_encrypt_data_len())
	{
		ulEncrypted_len = 1024;
		lRslt = app_encrypt_update(hdev, app_id, cont_id, pkey->key_id(), header, _lastlen, encrypted_ptr, (int *)&ulEncrypted_len);
		ERROR_THROW_APDU(lRslt)

		ulEncryptedTempdatalen += ulEncrypted_len;
		encrypted_ptr += ulEncrypted_len;

		pkey->get_stream_mgr()->pop_data(_lastlen);
	}

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	ulEncrypted_len = 1024;
	memcpy(pFinalData, header, _lastlen);
	lRslt = app_encrypt_final(hdev, app_id, cont_id, pkey->key_id(), pFinalData, _lastlen, encrypted_ptr, (int *)&ulEncrypted_len);
	ERROR_THROW_APDU(lRslt)

	encrypted_ptr += ulEncrypted_len;
	ulEncryptedTempdatalen += ulEncrypted_len;

	TRACE_ASSERT_LEN(*pulEncryptedLen, ulEncryptedTempdatalen)

	memcpy(pbEncryptedData, pEncrytedTempdata, ulEncryptedTempdatalen);
	*pulEncryptedLen = ulEncryptedTempdatalen;

	pkey->get_stream_mgr()->release();

END_OF_FUN:
	DELETE_BUFFER_PTR(pEncrytedTempdata)
		DBG_LOGMSG("leave SKF_Encrypt(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_EncryptUpdate(HANDLE hKey, BYTE * pbData, ULONG ulDataLen, BYTE *pbEncryptedData, ULONG *pulEncryptedLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_EncryptUpdate(), ulDataLen=%ld", ulDataLen);

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	ULONG			ulEncryptedTempdatalen = 0;
	ULONG			ulEncrypted_len = ulDataLen + get_max_transmit_len();
	BYTE			*pEncrytedTempdata = NULL;
	BYTE			*encrypted_ptr = NULL;
	int				_lastlen = 0;
	int				block_size = 0;
	BYTE			*header = NULL;
	int expSize = 0;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;
	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_EncryptUpdateHS(hKey, pbData, ulDataLen, pbEncryptedData, pulEncryptedLen);
	}
	
	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	block_size = pkey->get_block_size();

	if(pbEncryptedData == NULL)
	{
		*pulEncryptedLen = pkey->get_block_align_result_len(ulDataLen + _lastlen);
		goto END_OF_FUN;
	}

	expSize = pkey->get_block_align_result_len(ulDataLen + _lastlen);
	TRACE_ASSERT_LEN(*pulEncryptedLen, expSize);

	ulEncrypted_len = expSize + get_max_transmit_len();
	pEncrytedTempdata = new BYTE[ulEncrypted_len];
	memset(pEncrytedTempdata, 0, ulEncrypted_len);

	encrypted_ptr = pEncrytedTempdata;

	header = pkey->get_stream_mgr()->push_data(pbData, ulDataLen);

	while(_lastlen = pkey->get_encrypt_data_len())
	{
		ulEncrypted_len = get_max_transmit_len();
		
		lRslt = app_encrypt_update(hdev, app_id, cont_id, pkey->key_id(), header, _lastlen, encrypted_ptr, (int *)&ulEncrypted_len);
		ERROR_THROW_APDU(lRslt)
		
		ulEncryptedTempdatalen += ulEncrypted_len;
		encrypted_ptr = encrypted_ptr + ulEncrypted_len;

		pkey->get_stream_mgr()->pop_data(_lastlen);
	}

	TRACE_ASSERT_LEN(*pulEncryptedLen, ulEncryptedTempdatalen)

	memcpy(pbEncryptedData, pEncrytedTempdata, ulEncryptedTempdatalen);
	*pulEncryptedLen = ulEncryptedTempdatalen;

END_OF_FUN:
	DELETE_BUFFER_PTR(pEncrytedTempdata)
	DBG_LOGMSG("leave SKF_EncryptUpdate(), ret=%08x", lRslt);
	
	return lRslt;
}

ULONG DEVAPI SKF_EncryptFinal (HANDLE hKey, BYTE *pbEncryptedData, ULONG *ulEncryptedDataLen )
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_EncryptFinal()");

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	ULONG			ulEncrypted_len = get_max_transmit_len();
	BYTE			*pEncrytedTempdata = new BYTE[ulEncrypted_len];
	BYTE			*encrypted_ptr = pEncrytedTempdata;
	BYTE			pFinalData[32] = {0};
	ULONG			ulEncrytedTempdataLen = 0;
	int				data_len = 0;
	int				block_size;
	int				_lastlen =0;
	BYTE			*header = 0;
	int				expSize = 0;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;
	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_EncryptFinalHS(hKey, pbEncryptedData, ulEncryptedDataLen);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	header = pkey->get_stream_mgr()->get_data_ptr();

	block_size = pkey->get_block_size();
	data_len = (_lastlen/block_size) * block_size;

	expSize = pkey->get_padding_result_len(_lastlen);
	if(pbEncryptedData == NULL)
	{
		*ulEncryptedDataLen = expSize;
		goto END_OF_FUN;
	}

	if(SAR_OK != pkey->check_alg_data_len(_lastlen))
	{
		lRslt = SAR_INVALIDPARAMERR;
		goto END_OF_FUN;
	}

	TRACE_ASSERT_LEN(*ulEncryptedDataLen, expSize)
 	memset(pEncrytedTempdata, 0, sizeof(pEncrytedTempdata));

	if(data_len > 0)
	{
		lRslt = app_encrypt_update(hdev, app_id, cont_id, pkey->key_id(), header, data_len, encrypted_ptr, (int *)&ulEncrypted_len);
		ERROR_THROW_APDU(lRslt);

		encrypted_ptr += ulEncrypted_len;
		ulEncrytedTempdataLen += ulEncrypted_len;

		pkey->get_stream_mgr()->pop_data(data_len);
	}

	_lastlen = pkey->get_stream_mgr()->get_data_len();

	ulEncrypted_len = get_max_transmit_len();
	lRslt = app_encrypt_final(hdev, app_id, cont_id, pkey->key_id(), header, _lastlen,
		encrypted_ptr, (int *)&ulEncrypted_len);
	ERROR_THROW_APDU(lRslt)

	ulEncrytedTempdataLen += ulEncrypted_len;
	
	TRACE_ASSERT_LEN(*ulEncryptedDataLen, ulEncrytedTempdataLen)

	memcpy(pbEncryptedData, pEncrytedTempdata, ulEncrytedTempdataLen);
	*ulEncryptedDataLen = ulEncrytedTempdataLen;

	pkey->get_stream_mgr()->release();

END_OF_FUN:
	DELETE_BUFFER_PTR(pEncrytedTempdata)
	DBG_LOGMSG("leave SKF_EncryptFinal(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_DecryptInit (HANDLE hKey, BLOCKCIPHERPARAM DecryptParam)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_DecryptInit()");

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	int maxTrans = 0;
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_DecryptInitHS(hKey, DecryptParam);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();


	lRslt = app_decrypt_init(hdev, app_id, cont_id, pkey->key_id(), 
					DecryptParam.IV, DecryptParam.IVLen, 
					DecryptParam.PaddingType, DecryptParam.FeedBitLen);

	ERROR_THROW_APDU(lRslt)

	pkey->set_padding_type(DecryptParam.PaddingType);

	maxTrans = pDev->get_max_apdu_len();
	pkey->init_mem_stream(maxTrans * 2);

END_OF_FUN:
	DBG_LOGMSG("leave SKF_DecryptInit(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_Decrypt(HANDLE hKey, BYTE *pbEncryptedData, ULONG ulEncryptedLen, BYTE * pbData, ULONG * pulDataLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_Decrypt(), ulEncryptedLen=%ld", ulEncryptedLen);

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	ULONG			ulDecryptedTempdatalen = 0;
	ULONG			ulDecrypted_len = ulEncryptedLen;
	BYTE			*pDecrytedTempdata = new BYTE[ulEncryptedLen];
	BYTE			*pDecryted_ptr = pDecrytedTempdata;
	BYTE			pFinalData[32] = {0};
	int				_lastlen = 0;
	BYTE			*header = NULL;

	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;	
	gm_sc_key		*pkey = NULL;
	if(pbData == NULL)
	{
		*pulDataLen = ulEncryptedLen;
		goto END_OF_FUN;
	}

	pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_DecryptHS(hKey, pbEncryptedData, ulEncryptedLen, pbData, pulDataLen);
	}

	TRACE_ASSERT_LEN(*pulDataLen, ulEncryptedLen);

	if(ulEncryptedLen % pkey->get_block_size())
	{
		lRslt = SAR_INDATALENERR;
		goto END_OF_FUN;
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	header = pkey->get_stream_mgr()->push_data(pbEncryptedData, ulEncryptedLen);
	memset(pDecrytedTempdata, 0, ulEncryptedLen);

	while(_lastlen = pkey->get_decrypt_data_len())
	{
		ulDecrypted_len = ulEncryptedLen;
		lRslt = app_decrypt_update(hdev, app_id, cont_id, pkey->key_id(), header, _lastlen, pDecryted_ptr, (int *)&ulDecrypted_len);
		ERROR_THROW_APDU(lRslt);

		ulDecryptedTempdatalen += ulDecrypted_len;
		pDecryted_ptr += ulDecrypted_len;

		pkey->get_stream_mgr()->pop_data(_lastlen);
	}

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	memcpy(pFinalData, header, _lastlen);

	ulDecrypted_len = _lastlen;
	lRslt = app_decrypt_final(hdev, app_id, cont_id, pkey->key_id(), pFinalData, _lastlen, pDecryted_ptr, (int *)&ulDecrypted_len);
	ERROR_THROW_APDU(lRslt);

	ulDecryptedTempdatalen += ulDecrypted_len;

 	pkey->get_stream_mgr()->release();

	TRACE_ASSERT_LEN(*pulDataLen, ulDecryptedTempdatalen)

	memcpy(pbData, pDecrytedTempdata, ulDecryptedTempdatalen);
	*pulDataLen = ulDecryptedTempdatalen;

END_OF_FUN:
	DELETE_BUFFER_PTR(pDecrytedTempdata);
	DBG_LOGMSG("leave SKF_Decrypt(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_DecryptUpdate(HANDLE hKey, BYTE *pbEncryptedData, ULONG ulEncryptedLen, BYTE * pbData, ULONG * pulDataLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_DecryptUpdate(), ulEncryptedLen=%ld", ulEncryptedLen);

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	ULONG			ulDecryptedTempdatalen = 0;
	ULONG			ulDecrypted_len = ulEncryptedLen + get_max_transmit_len();
	BYTE			*pDecrytedTempdata = NULL;
	BYTE			*pDecryted_ptr = NULL;
	int				_lastlen = 0;
	BYTE			*header = NULL;

	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_DecryptUpdateHS(hKey, pbEncryptedData, ulEncryptedLen, pbData, pulDataLen);
	}

	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	_lastlen = pkey->get_stream_mgr()->get_data_len();

	if(pbData == NULL)
	{
		*pulDataLen = pkey->get_block_align_result_len(_lastlen + ulEncryptedLen);
		goto END_OF_FUN;
	}

	ulDecrypted_len = _lastlen + ulEncryptedLen + get_max_transmit_len();
	pDecrytedTempdata = new BYTE[ulDecrypted_len];
	memset(pDecrytedTempdata, 0, ulDecrypted_len);

	pDecryted_ptr = pDecrytedTempdata;

	header = pkey->get_stream_mgr()->push_data(pbEncryptedData, ulEncryptedLen);

	while(_lastlen = pkey->get_decrypt_data_len())
	{
		ulDecrypted_len = _lastlen;
		lRslt = app_decrypt_update(hdev, app_id, cont_id, pkey->key_id(), header, _lastlen, pDecryted_ptr, (int *)&ulDecrypted_len);
		ERROR_THROW_APDU(lRslt);

		ulDecryptedTempdatalen += ulDecrypted_len;
		pDecryted_ptr = pDecryted_ptr + ulDecrypted_len;
		pkey->get_stream_mgr()->pop_data(_lastlen);
	}

	TRACE_ASSERT_LEN(*pulDataLen, ulDecryptedTempdatalen);

	memcpy(pbData, pDecrytedTempdata, ulDecryptedTempdatalen);
	*pulDataLen = ulDecryptedTempdatalen;

END_OF_FUN:
	DELETE_BUFFER_PTR(pDecrytedTempdata)
	DBG_LOGMSG("leave SKF_DecryptUpdate(), ret=%08x", lRslt);
	return lRslt;
}

ULONG DEVAPI SKF_DecryptFinal (HANDLE hKey, BYTE *pbPlainText, ULONG *pulPlainTextLen)
{
	MK_AUTO_MUTEX
	DBG_LOGMSG("enter SKF_DecryptFinal(), pulPlainTextLen=%ld", pulPlainTextLen);

	ULONG			lRslt = SAR_OK;
	HANDLE			hdev;
	ULONG			app_id, cont_id;
	ULONG			output_len = 0;
	ULONG			ulDecrypted_len = get_max_transmit_len();
	BYTE			*pDecrytedTempdata = new BYTE[ulDecrypted_len];
	BYTE			*pDecryted_ptr = pDecrytedTempdata;
	int				data_len = 256;
	int				_lastlen = 0;
	BYTE			*header = NULL;
	
	gm_sc_dev * pDev = NULL;
	gm_sc_app * pApp = NULL;
	gm_sc_cont * pCont = NULL;

	gm_sc_key		*pkey = gm_sc_mgr::get_dev_ptr()->find_key(hKey, pDev, pApp, pCont);
	if(!pkey)
	{
		lRslt = SAR_INVALIDHANDLEERR;
		ERROR_THROW(lRslt);
	}

	//if high speed device
	if(pDev->if_support_hs())
	{
		return SKF_DecryptFinalHS(hKey, pbPlainText, pulPlainTextLen);
	}
 
	app_id = pApp->id();
	cont_id = pCont->id();
	hdev = pDev->get_apdu_handle();

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	header = pkey->get_stream_mgr()->get_data_ptr();

	if(pbPlainText == NULL)
	{
		*pulPlainTextLen = _lastlen;
		goto END_OF_FUN;
	}

	if(_lastlen % pkey->get_block_size())
	{
		lRslt = SAR_INDATALENERR;
		goto END_OF_FUN;
	}

	memset(pDecrytedTempdata, 0, sizeof(pDecrytedTempdata));
	data_len = (_lastlen/pkey->get_block_size() -1) * pkey->get_block_size();

	if(data_len < 0)
		data_len = 0;

	if(data_len)
	{
		lRslt = app_decrypt_update(hdev, app_id, cont_id, pkey->key_id(), header, data_len, pDecryted_ptr, (int *)&ulDecrypted_len);
		ERROR_THROW_APDU(lRslt)

		output_len += ulDecrypted_len;
		pDecryted_ptr += ulDecrypted_len;
		pkey->get_stream_mgr()->pop_data(data_len);
	}

	_lastlen = pkey->get_stream_mgr()->get_data_len();
	lRslt = app_decrypt_final(hdev, app_id, cont_id, pkey->key_id(), header, _lastlen, pDecryted_ptr, (int *)&ulDecrypted_len);
	ERROR_THROW_APDU(lRslt);

	output_len += ulDecrypted_len;

	TRACE_ASSERT_LEN(*pulPlainTextLen, output_len)

	memcpy(pbPlainText, pDecrytedTempdata, output_len);
	*pulPlainTextLen = output_len;
	pkey->get_stream_mgr()->release();
END_OF_FUN:
	DELETE_BUFFER_PTR(pDecrytedTempdata)
	DBG_LOGMSG("leave SKF_DecryptFinal(), ret=%08x", lRslt);
	return lRslt;
}
